#!/usr/bin/python
# -*- coding:utf-8 -*-
# @time: 2021/5/27 5:32 下午

from rest_framework import status
from rest_framework.response import Response
from rest_framework import mixins
from rest_framework.viewsets import ViewSetMixin
from rest_framework_mongoengine.generics import GenericAPIView


class CustomCreateModelMixin(mixins.CreateModelMixin):
    def create(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        self.perform_create(serializer)
        headers = self.get_success_headers(serializer.data)
        result = {"status": "success", "errcode": 0, "data": serializer.data}
        return Response(result, status=status.HTTP_201_CREATED, headers=headers)


class CustomRetrieveModelMixin(mixins.RetrieveModelMixin):
    def retrieve(self, request, *args, **kwargs):
        instance = self.get_object()
        serializer = self.get_serializer(instance)
        result = {"status": "success", "errcode": 0, "data": serializer.data}
        return Response(result)


class CustomUpdateModelMixin:
    def update(self, request, *args, **kwargs):
        partial = kwargs.pop('partial', False)
        instance = self.get_object()
        serializer = self.get_serializer(instance, data=request.data, partial=partial)
        serializer.is_valid(raise_exception=True)
        self.perform_update(serializer)

        if getattr(instance, '_prefetched_objects_cache', None):
            # If 'prefetch_related' has been applied to a queryset, we need to
            # forcibly invalidate the prefetch cache on the instance.
            instance._prefetched_objects_cache = {}
        result = {"status": "success", "errcode": 0, "data": serializer.data}
        return Response(result)

    def perform_update(self, serializer):
        serializer.save()


class CustomDestroyModelMixin(mixins.DestroyModelMixin):
    def destroy(self, request, *args, **kwargs):
        instance = self.get_object()
        self.perform_destroy(instance)
        result = {"status": "success", "errcode": 0, "message": "删除成功!"}
        return Response(result, status=status.HTTP_200_OK)


class CustomListModelMixin(mixins.ListModelMixin):
    def list(self, request, *args, **kwargs):
        queryset = self.filter_queryset(self.get_queryset())
        page = self.paginate_queryset(queryset)
        if page is not None:
            serializer = self.get_serializer(page, many=True)
            return self.get_paginated_response(serializer.data)

        serializer = self.get_serializer(queryset, many=True)
        result = {"status": "success", "errcode": 0, "data": serializer.data}
        return Response(result)


class CustomGenericViewSet(ViewSetMixin, GenericAPIView):
    """Adaptation of DRF GenericViewSet"""

    pass


class CustomModelViewSet(
    CustomCreateModelMixin,
    CustomRetrieveModelMixin,
    CustomUpdateModelMixin,
    CustomDestroyModelMixin,
    CustomListModelMixin,
    CustomGenericViewSet,
):
    """Adaptation of DRF ModelViewSet"""

    pass


class CustomReadOnlyModelViewSet(
    CustomRetrieveModelMixin, CustomListModelMixin, CustomGenericViewSet
):
    """Adaptation of DRF ReadOnlyModelViewSet"""

    pass


class CustomRetrieveUpdateAPIView(
    CustomRetrieveModelMixin, CustomUpdateModelMixin, GenericAPIView
):
    """Adaptation of DRF RetrieveUpdateAPIView"""

    def get(self, request, *args, **kwargs):
        return self.retrieve(request, *args, **kwargs)

    def put(self, request, *args, **kwargs):
        return self.update(request, *args, **kwargs)


class CustomCreateListDeleteAPIView(
    CustomCreateModelMixin,
    CustomListModelMixin,
    CustomDestroyModelMixin,
    CustomGenericViewSet,
):
    def get(self, request, *args, **kwargs):
        return self.list(request, *args, **kwargs)

    def post(self, request, *args, **kwargs):
        return self.create(request, *args, **kwargs)

    def delete(self, request, *args, **kwargs):
        result = self.destroy(request, *args, **kwargs)
        return result


class CustomRetrieveAPIView(CustomRetrieveModelMixin, GenericAPIView):
    """Adaptation of DRF RetrieveUpdateAPIView"""

    def get(self, request, *args, **kwargs):
        return self.retrieve(request, *args, **kwargs)
